package space.xiaoyuan.middleware.db.router.strategy.impl;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import space.xiaoyuan.middleware.db.router.DBContextHolder;
import space.xiaoyuan.middleware.db.router.DBRouterConfig;
import space.xiaoyuan.middleware.db.router.strategy.IDBRouterStrategy;

public class DBRouterStrategyHashCode implements IDBRouterStrategy {
    private final DBRouterConfig dbRouterConfig;
    private final Logger logger = LoggerFactory.getLogger(DBRouterStrategyHashCode.class);

    public DBRouterStrategyHashCode(DBRouterConfig dbRouterConfig) {
        this.dbRouterConfig = dbRouterConfig;
    }

    @Override
    public void doRouter(String dbKeyAttr) {
        int size = dbRouterConfig.getDbCount() * dbRouterConfig.getTbCount();
        // 扰动函数 & 分库分表量 得出下标
        int idx = (dbKeyAttr.hashCode() ^ dbKeyAttr.hashCode() >>> 16) & (size - 1);
        // 补充视频教程；https://t.zsxq.com/0f8PDPWtK - 评论区还有计算的图稿
        /**
         * idx / dbRouterConfig.getTbCount() + 1 => 可以得出在哪个库，
         * 例如： 每个库4个分表，idx散列得出5，那么5/4 + 1 = 1+1 = 2，那么就在第二个库
         * idx 散列得出取值范围 0 ~ size -1 ，所以dbIdx最大不超过DbCount
         *
         * int tbIdx = idx - dbRouterConfig.getTbCount() * (dbIdx - 1);
         * 例如： 5 - 4 * 1 = 1 在第一个表
         */
        int dbIdx = idx / dbRouterConfig.getTbCount() + 1;
        int tbIdx = idx - dbRouterConfig.getTbCount() * (dbIdx - 1) ;
        DBContextHolder.setDBKey(String.format("%02d", dbIdx));
        DBContextHolder.setTBKey(String.format("%03d", tbIdx));
        //logger.info("{},数据库路由 dbIdx：{} tbIdx：{}", dbKeyAttr, String.format("%02d", dbIdx), String.format("%03d", tbIdx));
    }

    @Override
    public void setDBKey(int dbIdx) {
        DBContextHolder.setDBKey(String.format("%02d",dbIdx));
    }

    @Override
    public void setTBKey(int tbIdx) {
        DBContextHolder.setTBKey(String.format("%03d",tbIdx));
    }

    @Override
    public int dbCount() {
        return dbRouterConfig.getDbCount();
    }

    @Override
    public int tbCount() {
        return dbRouterConfig.getTbCount();
    }

    @Override
    public void clear() {
        DBContextHolder.clearDBKey();
        DBContextHolder.clearTBKey();
    }
}
